"use strict";
const TWEEN = require("./Tween").default
const FM = require("./FoodManager");
const FoodEffect = FM.FoodEffect;
const Food = FM.Food;
const FoodSet = FM.FoodSet;
const FoodSetManager = FM.FoodSetManager;
// 将要回收的点，可进行重复利用
const CG_points = [];

function popCGPoint() {
	return CG_points.pop() || {
		x: 0,
		y: 0
	};
};

/**单位时间内的偏移量*/
const base_speed = 5;

// /**两点之间基础间隔 */
// const base_spacing = 5;

/**单位时间内的旋转量*/
const base_deg = 36;

var _pre_time = Date.now();
const ani_funs = [];
setInterval(() => {
	var _cur_time = Date.now();
	var _dif_time = _cur_time - _pre_time;
	ani_funs.forEach(fun => fun(_dif_time))
	_pre_time = _cur_time;
}, 1000 / 60)

class Snake {
	constructor(snake_shape, head_x, head_y) {
		this._base_spacing = 5;
		this.importData(snake_shape, head_x, head_y);
		this._ani_move();
		// this._ANI = new TWEEN();
	}
	importData(snake_shape, head_x, head_y) {
		const base_spacing = 5; //this._base_spacing = snake_shape._base_spacing || 5;

		this.id = snake_shape.id || Math.random().toString(36).substr(2);
		this.rid = snake_shape.rid;
		this.body_length = snake_shape.body_length < 3 * base_spacing ? 3 * base_spacing : snake_shape.body_length;

		var points = this.points = snake_shape.points || [{ //需要使用三个点来进行初始化
			x: head_x,
			y: head_y
		}, {
			x: head_x,
			y: head_y
		}, {
			x: head_x,
			y: head_y
		}];

		this.density = snake_shape.density;
		this.speed = snake_shape.speed;
		this.sensitivity = snake_shape.sensitivity;
		this.direction = snake_shape.direction;

		//将要增长的长度
		if (!snake_shape.delay_num) {
			var current_body_length = this.getBodyLength();
			this.delay_num = this.body_length - current_body_length;
			this.body_length = current_body_length;
		} else {
			this.delay_num = snake_shape.delay_num
		}
		/**方向延迟增长 */
		this.delay_deg = snake_shape.delay_deg || 0;
		/**方向旋转的时候是否顺时针 */
		this.is_clockwise = snake_shape.is_clockwise || true;

		this.is_ignore = snake_shape.is_ignore || false;
		this.is_stop = snake_shape.is_stop || false;
	}
	_ani_move() {
		ani_funs.push(this.update.bind(this));
		ani_funs.push(this.updateDirection.bind(this));
		// ani_funs.push(() => {
		// 	this._ANI.update()
		// });
	};
	update(delay_time) {
		if (this.is_stop) {
			return
		}
		const base_spacing = this._base_spacing;
		console.log(base_spacing);
		// 这条蛇进行一次偏移所需要的时间
		const unit_time = base_speed / this.speed * 100;
		// 这次运动计算的偏移比例
		const p = delay_time / unit_time;
		var points = this.points

		var source_distance = base_speed * p;
		var current_delay_num = this.delay_num;

		var distance = source_distance;
		if (current_delay_num < 0) {
			if (-current_delay_num >= source_distance) {
				var distance = 0;
				current_delay_num += source_distance
			} else {
				var distance = source_distance + current_delay_num;
				current_delay_num = 0;
			}
		}
		if (distance) {
			for (var len = points.length, cur_index = len - 2, nex_index = cur_index + 1; distance > 0; cur_index += 1, nex_index = cur_index + 1) {
				var nex_point = points[nex_index];
				var cur_point = points[cur_index];
				var point_dis = 0;

				if (nex_point) {
					point_dis = Math.sqrt(Math.pow(nex_point.x - cur_point.x, 2) + Math.pow(nex_point.y - cur_point.y, 2));
				}
				/**
				 * 距离为空有两种情况，
				 * 一种是：最后两个顶点之间没有距离，就无法确定xy_rate
				 * 一种是：nex_index > points.length - 1，属于超过最后一个顶点的新店
				 */
				if (!point_dis) { //使用_direction属性
					var xy_rate = Math.tan((this.direction / 180) * Math.PI);
					var symbol_x = this.direction < 180 ? 1 : -1;
					var symbol_y = this.direction > 90 && this.direction < 270 ? -1 : 1;
				} else { //依据两点之间本有的方向
					var xy_rate = (nex_point.x - cur_point.x) / (nex_point.y - cur_point.y);
					var symbol_x = nex_point.x > cur_point.x ? 1 : -1;
					var symbol_y = nex_point.y > cur_point.y ? 1 : -1;
				}
				if (!point_dis) { //没顶点或者顶点距离为0，或者是头部的顶点，直接使用方向来操作
					// console.log("add point")

					nex_point = popCGPoint();
					points.push(nex_point);

					var move_dis = Math.min(distance, base_spacing);
					distance -= move_dis;

					// } else if (point_dis === base_spacing) { //间距刚好，直接跳过这个点
					// 	continue;
					// } else if (point_dis > base_spacing) { //当前两点之间的距离过大，校准距离
					// 	var move_dis = base_spacing; //这个点后移
					// 	distance += point_dis - base_spacing; //增加偏移量
				} else if (point_dis >= base_spacing) { //间距刚好，直接跳过这个点
					continue;
				} else { //两点之间有可增长的空隙
					var move_dis = Math.min(distance + point_dis, //如果增长空间足够用
						base_spacing);
					distance -= move_dis - point_dis;
				}
				var xy_rate_pow_2 = xy_rate * xy_rate;
				var add_x = symbol_x * move_dis / Math.sqrt(1 + 1 / xy_rate_pow_2);
				var add_y = symbol_y * move_dis / Math.sqrt(1 + xy_rate_pow_2);

				var nex_x = cur_point.x + add_x;
				var nex_y = cur_point.y + add_y;
				if (nex_x === cur_point.x && nex_y === cur_point.y) { //如果这次增长两点之间的距离实在太短，不管，直接移除这个点
					points.pop();
				} else {
					nex_point.x = nex_x;
					nex_point.y = nex_y;
				}

			}
		}


		var distance = source_distance;
		if (current_delay_num > 0) {
			if (current_delay_num >= source_distance) {
				var distance = 0;
				current_delay_num -= source_distance
			} else {
				var distance = source_distance - current_delay_num;
				current_delay_num = 0;
			}
		}

		if (distance) {
			for (var cur_index = 1, pre_index = 0, len = points.length; distance > 0; cur_index += 1, pre_index = cur_index - 1) {
				var pre_point = points[pre_index];
				var cur_point = points[cur_index];
				var point_dis = Math.sqrt(Math.pow(cur_point.x - pre_point.x, 2) + Math.pow(cur_point.y - pre_point.y, 2));
				var move_dis = Math.min(distance, base_spacing); //所要缩短的距离
				if (move_dis >= point_dis) { //点距离不够，移除点
					distance -= point_dis;

					CG_points.push(pre_point);
					points.splice(pre_index, 1);
					cur_index -= 1;
					// console.log("remove point:", distance, point_dis);
				} else { //点距离溢出，缩短点之间的距离
					distance -= move_dis;

					var xy_rate_pow_2 = Math.pow((cur_point.x - pre_point.x) / (cur_point.y - pre_point.y), 2);
					var symbol_x = pre_point.x > cur_point.x ? 1 : -1;
					var symbol_y = pre_point.y > cur_point.y ? 1 : -1;
					var cut_x = symbol_x * (point_dis - move_dis) / Math.sqrt(1 + 1 / xy_rate_pow_2);
					var cut_y = symbol_y * (point_dis - move_dis) / Math.sqrt(1 + xy_rate_pow_2);

					// console.log("cut_x:", [cur_point.x, pre_point.x, cut_x], "cut_y:", [cur_point.y, pre_point.y, cut_y]);
					pre_point.x = cur_point.x + cut_x;
					pre_point.y = cur_point.y + cut_y;
					break;
				}
			}
		}

		this.body_length += this.delay_num - current_delay_num;
		this.delay_num = current_delay_num;
		this.density = Math.cbrt(this.body_length * 2) + 12;
		this._base_spacing = Math.cbrt(this.body_length * 2);
	};
	getBodyLength() {
		const points = this.points;
		var pre_point;
		var total_body_length = 0;
		for (var cur_point of points) {
			if (!cur_point) {
				break;
			}
			if (!pre_point) {
				pre_point = cur_point;
				continue;
			}
			total_body_length += Math.sqrt(Math.pow(cur_point.x - pre_point.x, 2) + Math.pow(cur_point.y - pre_point.y, 2))
			pre_point = cur_point;
		}
		return total_body_length;
	}
	addBody(num) {
		this.delay_num += num;
	}
	addSpeed(num) {
		this.speed += num;
	}
	addSensitivity(num) {
		this.sensitivity += num;
	}
	turnHead(deg) {
		var _direction = this.direction;
		var dif_deg = Math.abs(deg - _direction);
		if (!dif_deg) {
			return
		}
		var _is_clockwise = false;

		// 顺时针的角度范围
		var _left_deg_range = _direction - 180;
		if (_direction < 180) {
			if (deg < _direction || deg > _left_deg_range + 360) {
				_is_clockwise = true
			}
		} else {
			if (deg > _left_deg_range && deg < _direction) {
				_is_clockwise = true
			}
		}

		if (dif_deg > 180) {
			this.delay_deg = 360 - dif_deg;
		} else {
			this.delay_deg = dif_deg;
		}
		this.is_clockwise = _is_clockwise;
	}
	updateDirection(delay_time) {
		if (this.is_stop) {
			return
		}
		var _delay_deg = this.delay_deg;
		if (!_delay_deg) {
			return
		}
		// 这条蛇进行一次转向所需要的时间
		const unit_time = 360 / this.sensitivity * 100;
		// 这次运动计算的旋转角度
		const deg = delay_time / unit_time * base_deg;
		if (deg < _delay_deg) {
			this.delay_deg -= deg;
			var move_deg = deg;
		} else {
			this.delay_deg = 0;
			move_deg = _delay_deg;
		}

		var _direction = this.direction
		if (this.is_clockwise) {
			_direction -= move_deg;
			if (_direction < 0) {
				_direction += 360
			}
		} else {
			_direction += move_deg;
			if (_direction >= 360) {
				_direction -= 360
			}
		}
		this.direction = _direction;
	}
	sprint(onBurn, onEmber) {
		const base_spacing = this._base_spacing
		if (this.getBodyLength() < base_spacing * 4 || this.is_sprint) {
			return false;
		}
		this._before_sprint_speed = this.speed;
		this._before_sprint_sensitivity = this.sensitivity;
		this.speed *= 2;
		this.sensitivity *= 3;
		this.is_sprint = true;
		var _dif_speed = this.speed - this._before_sprint_speed;
		var _pre_time = Date.now();

		const sprint_burn = () => {
			var _cur_time = Date.now();
			var _dif_time = Math.min(_cur_time - _pre_time, 100) * Math.random();
			var k = 0.4; //加速与燃烧的比例
			var burn_body = _dif_time / 1000 * _dif_speed * k;
			var current_body_length = this.getBodyLength() + this.delay_num;
			if (current_body_length - burn_body <= base_spacing * 4) {
				burn_body = current_body_length - base_spacing * 4
				var _is_ember = true;
			}
			this.delay_num -= burn_body;
			onBurn(burn_body);
			if (_is_ember) {
				this.stopSprint();
				onEmber();
			}
			_pre_time = _cur_time;
		};
		this._sprint_ti = setInterval(sprint_burn, 400);
		sprint_burn();
		return true;
	}
	stopSprint(cb) {
		if (this._before_sprint_speed) {
			this.speed = this._before_sprint_speed;
			this.sensitivity = this._before_sprint_sensitivity;
			this._before_sprint_speed = null;
			this._before_sprint_sensitivity = null;
			this.is_sprint = false;
			clearInterval(this._sprint_ti);
			return true;
		} else {
			return false;
		}
	}
	destroy() {
		CG_points.push.apply(CG_points, this.points);
		this.points.length = 0;
	}
	toJSON() {
		var res = Object.assign({}, this);
		res.is_clockwise = res.is_clockwise ? 1 : 0;
		res.is_ignore = res.is_ignore ? 1 : 0;
		res.is_stop = res.is_stop ? 1 : 0;
		res.is_sprint = res.is_sprint ? 1 : 0;
		delete res._before_sprint_speed;
		delete res._before_sprint_sensitivity;
		delete res._sprint_ti;
		delete res._base_spacing;
		// res.points = res.points.map(point => {
		// 	return {
		// 		x: Math.round(point.x),
		// 		y: Math.round(point.y),
		// 	}
		// })
		return res;
	}
	die() {
		var points = this.points;
		var density = this.density;
		var total_body = this.getBodyLength();
		var total_speed = this.speed;
		// var total_sensitivity = this.sensitivity;

		var unit_body = 1;
		var unit_speed = total_speed / total_speed;
		var unit_sensitivity = 2; //total_sensitivity / total_speed;

		var rem_body = total_body;
		var rem_speed = unit_speed * total_body;
		var rem_sensitivity = unit_sensitivity * total_body;

		var total_sensitivity = rem_sensitivity;

		var food_info_list = []
		points.forEach((point, i) => {
			var add_body = i * unit_body >= total_body - rem_body ? unit_body * Math.random() * 2 : 0
			rem_body -= add_body;
			var add_speed = i * unit_speed >= total_speed - rem_speed ? unit_speed * Math.round(Math.random() * 2) : 0
			rem_speed -= add_speed;
			var add_sensitivity = i * unit_sensitivity >= total_sensitivity - rem_sensitivity ? unit_sensitivity * Math.round(Math.random() * 2) : 0
			rem_sensitivity -= add_sensitivity;

			food_info_list.push(new Food(
				Math.round(point.x + (Math.random() - 0.5) * 2 * density),
				Math.round(point.y + (Math.random() - 0.5) * 2 * density),

				{
					add_body: add_body,
					add_speed: 0, //add_speed,
					add_sensitivity: 0, //add_sensitivity,
				}
			))
		});

		this.is_stop = true;
		this.is_ignore = true;
		this.destroy();
		return food_info_list;
	}
};
/**蛇的空间容器 
 * 容器是
 */
class SnakeSet extends Array {
	constructor() {

	}
	addSnake() {

	}
}
/**外部容器管理 */
class SnakeSetManager extends Array {

}

exports.Snake = Snake;
exports.SnakeSet = SnakeSet;
exports.SnakeSetManager = SnakeSetManager;